#pragma once
#ifndef _fastbird_Math_header_included_
#define _fastbird_Math_header_included_

namespace fastbird
{
	inline static bool IsNaN(float f);
}
#include <Engine/Math/Mat44.h>
#include <Engine/Math/Vec3.h>
#include <Engine/Math/Quat.h>

namespace fastbird
{
	static const float PI = 3.14159265358979f;
	static const float HALF_PI = 1.5707963f;
	static const float TWO_PI = 6.28318530f;
	static const float EPSILON = 1.192092896e-07F;
	static const float ZERO_TOLERANCE = 1e-06f;

	inline bool IsNaN(float f)
	{
		return f != f;
	}

	inline Mat44 MakeViewMatrix(const Vec3& pos, const Vec3& x, const Vec3& y, const Vec3& z)
	{
		// transposed
		Mat33 tansposedRot(
			x.x, x.y, x.z,
			y.x, y.y, y.z,
			z.x, z.y, z.z
			);
		Vec3 t = -(tansposedRot * pos);
		Mat44 viewMat(tansposedRot, t);
		Mat44 yzSwapMat(
			1, 0, 0, 0,
			0, 0, 1, 0,
			0, 1, 0, 0,
			0, 0, 0, 1);
		return viewMat;
	}

	//------------------------------------------------------------------------
	inline Mat44 MakeProjectionMatrix(float fov, float aspectRatio, float n, float f)
	{
		// Projection Matrix for D3D
		// [ d/a	0		0		0]
		// [ 0		d		0		0]
		// [ 0		0		f/(f-n) -n*f/(f-n)]
		// [ 0		0		1		0]

		const float d = 1.0f/tan(fov/2.f);
		const float DofA = d/aspectRatio;
		float A = f / (f-n);
		float B = -n*f / (f-n);

		return Mat44(
				DofA,	0,	0,	0,
				0,		d,	0,	0,
				0,		0,	A,	B,
				0,		0,	1,	0
				) ;
	}

	//------------------------------------------------------------------------
	inline Mat44 MakeOrthogonalMatrix(float l, float t, float r, float b, float n, float f)
	{
		// Orthogonal matrix for D3D
		// [2/(r-l)	0		0		-(r+l)/(r-l)]
		// [0		2/(t-b)	0		-(t+b)/(t-b)]
		// [0		0		1/(f-n)	-n/(f-n)]
		// [0		0		0		1]
		return Mat44(
			2.f/(r-l),	0,			0,	-(r+l)/(r-l),
			0,			2.f/(t-b),	0,	-(t+b)/(t-b),
			0,			0,			1.f/(f-n),	-n/(f-n),
			0,			0,			0,			1.f);
	}

	inline float Degree(float radian)
	{
		return radian / PI * 180.0f;
	}

	inline float Radian(float degree)
	{
		return degree / 180.0f * PI;
	}

	inline bool IsPowerOfTwo(int a)
	{
		return !(a & (a-1) );
	}

	template <class T>
	inline void Clamp(T& a, const T min, const T max)
	{
		if (a < min)
			a = min;
		else if (a>max)
			a = max;
	}

	template <class T>
	inline T Lerp(const T& a, const T& b, float lp)
	{
		return a * (1.0f-lp) + b * lp;
	}
}

#endif //_fastbird_Math_header_included_